"""
    pycoopiler - a compiler developed to PCS2056 course (Compilers) at Poli-USP
    Copyright (C) 2008 Andre Felipe Santos    
    Copyright (C) 2008 Rodrigo Rodrigues da Silva

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
"""

from token import *
from enum import enum

class tokenizer:
    
    states = enum("START CONST ID EXCL EQ GT LT")
    
    def __init__(self, file):
        self._file = file
        self.reading = ''
        self.current_char = ''
        self.current = None
        self.next_char()
        self.next_token()
        
    def next_char(self):
        if not self.current_char.isspace():
            self.reading += self.current_char
        self.current_char = self._file.read(1)
        
    def ret_token(self, type):
        self.current = token(self.reading, type)
        return self.current
        
    def current(self):
        return self.current
      
    def next_token(self):
        self.state = self.states.START
        self.reading = ''
        
        while True:            
            
            if self.state == self.states.START:
                
                if self.current_char.isdigit():
                    self.state = self.states.CONST
                    self.next_char()
                    
                elif self.current_char.isalpha():
                    self.state = self.states.ID
                    self.next_char() 
                       
                elif self.current_char == '!':
                    self.state = self.states.EXCL
                    self.next_char()    
                    
                elif self.current_char == '=':
                    self.state = self.states.EQ
                    self.next_char()    
                    
                elif self.current_char == '>':
                    self.state = self.states.GT
                    self.next_char()    
                    
                elif self.current_char == '<':
                    self.state = self.states.LT
                    self.next_char()
                    
                elif self.current_char == '(':
                    self.next_char()
                    return self.ret_token(token.types.OPEN_RB)
                
                elif self.current_char == ')':
                    self.next_char()
                    return self.ret_token(token.types.CLOSE_RB)
                    
                elif self.current_char == '{':
                    self.next_char()
                    return self.ret_token(token.types.OPEN_CB)
                
                elif self.current_char == '}':
                    self.next_char()
                    return self.ret_token(token.types.CLOSE_CB)
                    
                elif self.current_char == '[':
                    self.next_char()
                    return self.ret_token(token.types.OPEN_SB)
                
                elif self.current_char == ']':
                    self.next_char()
                    return self.ret_token(token.types.CLOSE_SB)
                
                elif self.current_char == '+':
                    self.next_char()
                    return self.ret_token(token.types.PLUS)
                
                elif self.current_char == '-':
                    self.next_char()
                    return self.ret_token(token.types.MINUS)
                
                elif self.current_char == '*':
                    self.next_char()
                    return self.ret_token(token.types.TIMES)
                
                elif self.current_char == '/':
                    self.next_char()
                    return self.ret_token(token.types.DIV)
                
                elif self.current_char == '%':
                    self.next_char()
                    return self.ret_token(token.types.MOD)
                
                elif self.current_char == '&':
                    self.next_char()
                    return self.ret_token(token.types.AND)
                
                elif self.current_char == '|':
                    self.next_char()
                    return self.ret_token(token.types.OR)
                
                elif self.current_char == ',':
                    self.next_char()
                    return self.ret_token(token.types.COMMA)
                
                elif self.current_char == ';':
                    self.next_char()
                    return self.ret_token(token.types.SEMICOLON)
                
                elif self.current_char == '':
                    return self.ret_token(token.types.EOF)
                
                elif not self.current_char.isspace():
                    raise Exception("Lexical error!")
                
                else:
                    self.next_char()
            
            elif self.state == self.states.CONST:
                if self.current_char.isdigit():
                    self.next_char()
                else:
                    return self.ret_token(token.types.CONST)

            elif self.state == self.states.ID:
                if self.current_char.isalnum():
                    self.next_char()
                else:
                    if self.reading == "int" : type =  token.types.INT
                    elif self.reading == "void" : type =  token.types.VOID
                    elif self.reading == "if" : type =  token.types.IF
                    elif self.reading == "while" : type =  token.types.WHILE
                    elif self.reading == "return" : type =  token.types.RETURN                    
                    elif self.reading == "print" : type =  token.types.PRINT
                    elif self.reading == "read" : type =  token.types.READ
                    else: type = token.types.ID
                    return self.ret_token(type)
                
            elif self.state == self.states.EXCL:
                if self.current_char == '=':
                    self.next_char()
                    return self.ret_token(token.types.DIFF)
                else:
                    return self.ret_token(token.types.NOT)
                
            elif self.state == self.states.EQ:
                if self.current_char == '=':
                    self.next_char()
                    return self.ret_token(token.types.COMP)
                else:
                    return self.ret_token(token.types.ATTR)
                
            elif self.state == self.states.GT:
                if self.current_char == '=':
                    self.next_char()
                    return self.ret_token(token.types.GTEQ)
                else:
                    return self.ret_token(token.types.GT)
                
            elif self.state == self.states.LT:
                if self.current_char == '=':
                    self.next_char()
                    return self.ret_token(token.types.LTEQ)
                else:
                    return self.ret_token(token.types.LT)
            
            else: raise Exception("Invalid state: " + self.state)